//////////////////////////////////////////////////////////////////////////////
//
// File:  parser.cc
//
// Description:
//  This is the implementation file for the parser and lineInfo classes.
//  These classes are used in the parsing of configuration files needed
//  for the bnet connection, and chat server/clients.
//
// 
// Config file requirements:
//   In the config file, the password entry is very picky.  Please make sure
//   that the password is separated by only 1 space from the word 'password'
//   in the file.  This password entry also cannot have any comments
//   within the line.
//  
//   ** Same goes for home_channel as well.
// 


#include <iostream>
#include <fstream>
#include <list>
#include <string>
#include <sstream>

#include "parser.h"

using namespace std;
#include <qtextstream.h>

extern QTextStream *Debug;

//////////////////////////////////////////////////////////////////////////////
//
//  Class parser
//
// 


// Default constructor.
parser::parser() {

}


// Alternate constructor.
parser::parser(string file) {
  // Parse the file.
  parse(file);       
}

parser::~parser() {
  if(toParse.is_open() == true) {
    toParse.close();
  }
  // just to be clean:
  configInfo.clear();
}

// Function:  parse()
// Input:     file to parse.
// Output:    configInfo.
// This function does pretty much everything.
bool parser::parse(string file) {

  // Close the whatever the old file was if the ifstream thinks
  //   there is one already open.
  if(toParse.is_open() == true) {
    toParse.close();
  }

  // Clear out the configInfo list.
  configInfo.clear();

  // Open the file.
  toParse.open(file.c_str());

  if(!toParse.is_open()) {
    return false;
  }

  // Parse the file & the store config info into configInfo.

  while(!toParse.eof()) {
    string currWord;          // Current working word.
    char buffer[256];         // Buffer for getline.
  
  
    // Get a line into the buffer
    toParse.getline(buffer, 256);

    // Turn the current line in the buffer to a stream.
    istringstream currLine(buffer);
  
    // Get the config for this line. (That is... if it's not a "" or comment)
    
    // Grab the first word.
    currLine >> currWord;

    // If it's not a comment and not an empty line, collect the
    //    next key & value.  Otherwise, proceed to next line.

    if((currWord.c_str()[0] != '#') && (currWord != "")) {
      // Yay, new config item!
      lineInfo configItem;
	
      // Store the key:
      configItem.key = currWord;

      if(configItem.key.substr(0, strlen("password")) == "password") {
	// Password parsing here is VERY picky to account for spaces
	//   that could be scattered among the password.
	// That means the password can't have unnecessary leading or
	//   trailing spaces.  It also means that there can't be any
	//   comments on this line.
	string password = string(&buffer[ configItem.key.size()+1 ]);
	
	// Store the value.
	configItem.value = password;
      }
      else if(configItem.key.substr(0, strlen("home_channel"))
	      == "home_channel") {
	// Same that went for password goes for home_channel
	string home = string(& buffer[ configItem.key.size()+1 ]);
	  
	// Store the value.
	configItem.value = home;
      }
      else {
	// Get the value of this config item;
	currLine >> currWord;

	// Store the value:
	configItem.value = currWord;
      }
	
	
      // Now push_back it onto the list.
      configInfo.push_back(configItem);
    }
    else {  // It's a comment or empty line...
      // Do nothing and go on to read the next line.
    }
  } // end of while(!toParse.eof())

  // Done with the file.  Return true.
  toParse.close();
  return true;
}


bool parser::fetch(string key, string &value) {
  // We want the value for the key given.

  // Iterate through da junx.
  for(list<lineInfo>::iterator It = configInfo.begin();
      It != configInfo.end(); It++) {

    // Working variable used to get the value.
    lineInfo currItem = *It;
    
    // We found what we're looking for!  
    if(currItem.key == key) {
      value = currItem.value;
      return true;
    }
  }
  
  // Damn.  Couldn't find the config entry.
  *Debug << "WARNING:  couldn't execute a fetch on the config file" << endl
	<< "         " << __FILE__ << "(" << __LINE__ << ")" << endl;

  return false;

}


bool parser::fetch(string key, bool &value) {
  // We want the value for the key given.

  // Iterate through da junx.
  for(list<lineInfo>::iterator It = configInfo.begin();
      It != configInfo.end(); It++) {

    // Working variable used to get the value.
    lineInfo currItem = *It;
    
    // We found what we're looking for!  
    if(currItem.key == key) {
      if(currItem.value == "on") {
	value = true;
      }
      else if (currItem.value == "off") {
	value = false;
      }
      else {
	return false;
      }
      return true;
    }
  }
  
  // Damn.  Couldn't find the config entry.
  *Debug << "WARNING:  couldn't execute a fetch on the config file" << endl
	<< "         " << __FILE__ << "(" << __LINE__ << ")" << endl;

  return false;

}



bool parser::fetch(string key, int &value) {
  // We want the value for the key given.

  // Iterate through da junx.
  for(list<lineInfo>::iterator It = configInfo.begin();
      It != configInfo.end(); It++) {

    // Working variable used to get the value.
    lineInfo currItem = *It;
    
    // We found what we're looking for!  
    if(currItem.key == key) {
      value = atoi(currItem.value.c_str());
      return true;
    }
  }
  
  // Damn.  Couldn't find the config entry.
  *Debug << "WARNING:  couldn't execute a fetch on the config file" << endl
	<< "         " << __FILE__ << "(" << __LINE__ << ")" << endl;

  return false;

}






